package com.wnxy.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;

/**
 * 基于Mybatis操作数据库的工具类
 */
public class DBUtil {

    private static SqlSessionFactory factory = null; //SqlSeesion工厂
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>(); // 本地线程变量的对象
    private static Logger logger = Logger.getLogger(DBUtil.class); // 日志记录器

    static{
        //1.创建一个工厂的建造者
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        try {
            //2.加载框架的核心配置文件（读取成一个IO流)
            InputStream inStream = Resources.getResourceAsStream("mybatis-config.xml");
            //3. 建造者开始建造SqlSeesion工厂
            factory = factoryBuilder.build(inStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession
     * factory.openSession() ： 获取的SqlSession需要手动提交（主要给事务使用）
     * factory.openSession(false) ： 获取的SqlSession需要手动提交（主要给事务使用）
     * factory.openSession(true) : 获取的SqlSession默认是自动提交的
     * @return
     */
    public static SqlSession openSqlSession(boolean flag){
        return  factory.openSession(flag); // 本质：从数据库连接池中获取一个数据库连接（默认是手动提交的）
    }

    /**
     * 获取与当前执行线程绑定的sqlSession
     * @return
     */
    public static SqlSession currentSqlSession(){
        // 先从执行的线程中去尝试获取绑定的sqlSession
        SqlSession sqlSession = threadLocal.get();
        if(sqlSession == null){
            sqlSession = openSqlSession(false); // 创建一个手动提交的sqlSession(事务专用)
            // 将新建的sqlSession与当前的执行线程绑定（本地线程变量）
            threadLocal.set(sqlSession);
        }
        return sqlSession;
    }

    /**
     * 开始数据库事务
     */
    public static void beginTransaction(){
        currentSqlSession();
        logger.debug("数据库事务开启...");
    }

    /**
     * 提交数据库事务
     */
    public static void commitTransaction(){
        SqlSession sqlSession = currentSqlSession();
        sqlSession.commit(); // 提交事务
        logger.debug("数据库事务已成功提交!");
    }

    /**
     * 回滚数据库事务
     * @cause 失败原因
     */
    public static void rollbackTransaction(String cause){
        SqlSession sqlSession = currentSqlSession();
        sqlSession.rollback(); //回滚数据
        logger.error("数据库事务失败【cause:"+cause+"】,数据正在回滚!");
    }

    /**
     * 释放资源
     */
    public static void release(){
        SqlSession sqlSession = currentSqlSession();
        sqlSession.close(); // 将sqlSession归还到Mybatis内置的数据库连接池中
        threadLocal.remove(); // 主要是为了防止内存泄漏
    }

}
